package com.moon.cloud.common.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 日期时间工具类
 */
public class DateUtils {

    public static final String PATTERN_HH_MM_SS = "HH:mm:ss";
    public static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String PATTERN_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";

    // 缓存DateTimeFormatter实例，避免重复创建
    private static final Map<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>();

    /**
     * 获取或创建 DateTimeFormatter
     */
    private static DateTimeFormatter getFormatter(String pattern) {
        return FORMATTER_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
    }

    // ==================== 格式化相关 ====================

    /**
     * 获取当前时间，并格式化为指定的模式
     */
    public static String getCurrentTime(String pattern) {
        return formatDate(LocalDateTime.now(), pattern);
    }

    /**
     * 格式化日期时间
     */
    public static String formatDate(LocalDateTime date, String pattern) {
        return date.format(getFormatter(pattern));
    }

    /**
     * 解析日期时间字符串
     */
    public static LocalDateTime parseDate(String dateString, String pattern) {
        return LocalDateTime.parse(dateString, getFormatter(pattern));
    }

    /**
     * 获取当前日期
     */
    public static String getCurrentDate(String pattern) {
        return formatLocalDate(LocalDate.now(), pattern);
    }

    /**
     * 格式化日期
     */
    public static String formatLocalDate(LocalDate date, String pattern) {
        return date.format(getFormatter(pattern));
    }

    /**
     * 解析日期字符串
     */
    public static LocalDate parseLocalDate(String dateString, String pattern) {
        return LocalDate.parse(dateString, getFormatter(pattern));
    }

    /**
     * 格式化时间
     */
    public static String formatLocalTime(LocalTime time, String pattern) {
        return time.format(getFormatter(pattern));
    }

    /**
     * 解析时间字符串
     */
    public static LocalTime parseLocalTime(String timeString, String pattern) {
        return LocalTime.parse(timeString, getFormatter(pattern));
    }

    // ==================== 获取开始时间 ====================

    /**
     * 获取今天开始时间（00:00:00）
     */
    public static LocalDateTime getTodayStart() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
    }

    /**
     * 获取今天结束时间（23:59:59.999999999）
     */
    public static LocalDateTime getTodayEnd() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
    }

    /**
     * 获取指定日期的开始时间（00:00:00）
     */
    public static LocalDateTime getDayStart(LocalDate date) {
        return LocalDateTime.of(date, LocalTime.MIN);
    }

    /**
     * 获取指定日期的结束时间（23:59:59.999999999）
     */
    public static LocalDateTime getDayEnd(LocalDate date) {
        return LocalDateTime.of(date, LocalTime.MAX);
    }

    /**
     * 获取本周开始时间（周一 00:00:00）
     */
    public static LocalDateTime getWeekStart() {
        LocalDate monday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        return LocalDateTime.of(monday, LocalTime.MIN);
    }

    /**
     * 获取本周结束时间（周日 23:59:59.999999999）
     */
    public static LocalDateTime getWeekEnd() {
        LocalDate sunday = LocalDate.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        return LocalDateTime.of(sunday, LocalTime.MAX);
    }

    /**
     * 获取本月开始时间（1号 00:00:00）
     */
    public static LocalDateTime getMonthStart() {
        LocalDate firstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        return LocalDateTime.of(firstDay, LocalTime.MIN);
    }

    /**
     * 获取本月结束时间（最后一天 23:59:59.999999999）
     */
    public static LocalDateTime getMonthEnd() {
        LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        return LocalDateTime.of(lastDay, LocalTime.MAX);
    }

    /**
     * 获取指定月份的开始时间
     */
    public static LocalDateTime getMonthStart(int year, int month) {
        LocalDate firstDay = LocalDate.of(year, month, 1);
        return LocalDateTime.of(firstDay, LocalTime.MIN);
    }

    /**
     * 获取指定月份的结束时间
     */
    public static LocalDateTime getMonthEnd(int year, int month) {
        LocalDate firstDay = LocalDate.of(year, month, 1);
        LocalDate lastDay = firstDay.with(TemporalAdjusters.lastDayOfMonth());
        return LocalDateTime.of(lastDay, LocalTime.MAX);
    }

    /**
     * 获取本年开始时间（1月1日 00:00:00）
     */
    public static LocalDateTime getYearStart() {
        LocalDate firstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfYear());
        return LocalDateTime.of(firstDay, LocalTime.MIN);
    }

    /**
     * 获取本年结束时间（12月31日 23:59:59.999999999）
     */
    public static LocalDateTime getYearEnd() {
        LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfYear());
        return LocalDateTime.of(lastDay, LocalTime.MAX);
    }

    /**
     * 获取指定年份的开始时间
     */
    public static LocalDateTime getYearStart(int year) {
        LocalDate firstDay = LocalDate.of(year, 1, 1);
        return LocalDateTime.of(firstDay, LocalTime.MIN);
    }

    /**
     * 获取指定年份的结束时间
     */
    public static LocalDateTime getYearEnd(int year) {
        LocalDate lastDay = LocalDate.of(year, 12, 31);
        return LocalDateTime.of(lastDay, LocalTime.MAX);
    }

    // ==================== 时间计算相关 ====================

    /**
     * 计算两个日期之间相差的天数
     */
    public static long betweenDays(LocalDate start, LocalDate end) {
        return ChronoUnit.DAYS.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的天数
     */
    public static long betweenDays(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.DAYS.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的小时数
     */
    public static long betweenHours(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.HOURS.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的分钟数
     */
    public static long betweenMinutes(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.MINUTES.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的秒数
     */
    public static long betweenSeconds(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.SECONDS.between(start, end);
    }

    /**
     * 计算两个日期之间相差的月数
     */
    public static long betweenMonths(LocalDate start, LocalDate end) {
        return ChronoUnit.MONTHS.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的月数
     */
    public static long betweenMonths(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.MONTHS.between(start, end);
    }

    /**
     * 计算两个日期之间相差的年数
     */
    public static long betweenYears(LocalDate start, LocalDate end) {
        return ChronoUnit.YEARS.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的年数
     */
    public static long betweenYears(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.YEARS.between(start, end);
    }

    /**
     * 计算两个日期时间之间相差的毫秒数
     */
    public static long betweenMillis(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.MILLIS.between(start, end);
    }

    // ==================== 日期时间加减 ====================

    /**
     * 日期加天数
     */
    public static LocalDate plusDays(LocalDate date, long days) {
        return date.plusDays(days);
    }

    /**
     * 日期减天数
     */
    public static LocalDate minusDays(LocalDate date, long days) {
        return date.minusDays(days);
    }

    /**
     * 日期时间加天数
     */
    public static LocalDateTime plusDays(LocalDateTime dateTime, long days) {
        return dateTime.plusDays(days);
    }

    /**
     * 日期时间减天数
     */
    public static LocalDateTime minusDays(LocalDateTime dateTime, long days) {
        return dateTime.minusDays(days);
    }

    /**
     * 日期时间加小时
     */
    public static LocalDateTime plusHours(LocalDateTime dateTime, long hours) {
        return dateTime.plusHours(hours);
    }

    /**
     * 日期时间减小时
     */
    public static LocalDateTime minusHours(LocalDateTime dateTime, long hours) {
        return dateTime.minusHours(hours);
    }

    /**
     * 日期时间加分钟
     */
    public static LocalDateTime plusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime.plusMinutes(minutes);
    }

    /**
     * 日期时间减分钟
     */
    public static LocalDateTime minusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime.minusMinutes(minutes);
    }

    /**
     * 日期加月数
     */
    public static LocalDate plusMonths(LocalDate date, long months) {
        return date.plusMonths(months);
    }

    /**
     * 日期减月数
     */
    public static LocalDate minusMonths(LocalDate date, long months) {
        return date.minusMonths(months);
    }

    /**
     * 日期加年数
     */
    public static LocalDate plusYears(LocalDate date, long years) {
        return date.plusYears(years);
    }

    /**
     * 日期减年数
     */
    public static LocalDate minusYears(LocalDate date, long years) {
        return date.minusYears(years);
    }

    // ==================== 日期时间比较 ====================

    /**
     * 判断日期是否在指定范围内（包含边界）
     */
    public static boolean isBetween(LocalDate date, LocalDate start, LocalDate end) {
        return !date.isBefore(start) && !date.isAfter(end);
    }

    /**
     * 判断日期时间是否在指定范围内（包含边界）
     */
    public static boolean isBetween(LocalDateTime dateTime, LocalDateTime start, LocalDateTime end) {
        return !dateTime.isBefore(start) && !dateTime.isAfter(end);
    }

    /**
     * 判断是否为今天
     */
    public static boolean isToday(LocalDate date) {
        return date.equals(LocalDate.now());
    }

    /**
     * 判断是否为今天
     */
    public static boolean isToday(LocalDateTime dateTime) {
        return dateTime.toLocalDate().equals(LocalDate.now());
    }

    /**
     * 判断是否为本周
     */
    public static boolean isThisWeek(LocalDate date) {
        LocalDate now = LocalDate.now();
        LocalDate weekStart = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate weekEnd = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        return isBetween(date, weekStart, weekEnd);
    }

    /**
     * 判断是否为本月
     */
    public static boolean isThisMonth(LocalDate date) {
        LocalDate now = LocalDate.now();
        return date.getYear() == now.getYear() && date.getMonth() == now.getMonth();
    }

    /**
     * 判断是否为本年
     */
    public static boolean isThisYear(LocalDate date) {
        return date.getYear() == LocalDate.now().getYear();
    }

    /**
     * 判断是否为周末（周六或周日）
     */
    public static boolean isWeekend(LocalDate date) {
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
    }

    /**
     * 判断是否为工作日（周一到周五）
     */
    public static boolean isWorkday(LocalDate date) {
        return !isWeekend(date);
    }

    // ==================== 其他实用方法 ====================

    /**
     * 获取指定日期是星期几（1-7，周一到周日）
     */
    public static int getDayOfWeek(LocalDate date) {
        return date.getDayOfWeek().getValue();
    }

    /**
     * 获取指定日期是当月的第几天
     */
    public static int getDayOfMonth(LocalDate date) {
        return date.getDayOfMonth();
    }

    /**
     * 获取指定日期是当年的第几天
     */
    public static int getDayOfYear(LocalDate date) {
        return date.getDayOfYear();
    }

    /**
     * 获取指定年月的天数
     */
    public static int getDaysOfMonth(int year, int month) {
        return YearMonth.of(year, month).lengthOfMonth();
    }

    /**
     * 获取指定日期所在月份的天数
     */
    public static int getDaysOfMonth(LocalDate date) {
        return date.lengthOfMonth();
    }

    /**
     * 判断是否为闰年
     */
    public static boolean isLeapYear(int year) {
        return Year.isLeap(year);
    }

    /**
     * 判断指定日期所在年份是否为闰年
     */
    public static boolean isLeapYear(LocalDate date) {
        return date.isLeapYear();
    }

    /**
     * 获取当前时间戳（毫秒）
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }

    /**
     * 获取当前时间戳（秒）
     */
    public static long getCurrentTimestampSeconds() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * LocalDateTime 转时间戳（毫秒）
     */
    public static long toTimestamp(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 时间戳（毫秒）转 LocalDateTime
     */
    public static LocalDateTime fromTimestamp(long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
    }
}
